﻿using Net;
using Net.Component;
using Net.Server;
using Net.Share;
using System;
using System.Collections.Generic;
using System.Linq;

namespace FPSServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Ser ser = new Ser();
            ser.Log += Console.WriteLine;
            ser.SetHeartTime(5,1000);
            ser.Run();
            while (true) { Console.ReadLine(); }
        }
    }

    public class PlayerData : ISerializableData
    {
        public string account { get { return UIDKey; } set { UIDKey = value; } }
        public string password;
        public string UIDKey { get; set; }
    }

    class Peer : NetPlayer
    {
        internal PlayerData data;
        internal Scene scene;
        internal float hp = 100;
        internal Vector3 position;
        internal Quaternion rotation;
        internal Vector3 direction;
        internal byte fire;
        internal byte jump;
        internal byte[] extraData=new byte[8];
        
        public override void OnStart()
        {
            position = new Vector3(RandomHelper.Range(-20f,20f), 2, RandomHelper.Range(-20f, 20f));
            hp = 100;
        }

        public override bool OnOperationSync(OperationList list)
        {
            foreach (var opt in list.operations) 
            {
                switch (opt.cmd) {
                    case Command.Damage:
                        if (scene.players.ContainsKey(opt.name1)) 
                        {
                            var p2 = scene.players[opt.name1];
                            if (p2.hp <= 0)
                                continue;
                            p2.hp -= opt.health;
                        }
                        break;
                    case Command.Input:
                        position = opt.position;
                        rotation = opt.rotation;
                        direction = opt.direction;
                        fire = opt.cmd1;
                        jump = opt.cmd2;
                        extraData = opt.buffer;
                        break;
                    case Command.EnemyDamage:
                        if (scene.enemies.ContainsKey(opt.name1))
                        {
                            var p2 = scene.enemies[opt.name1];
                            if (p2.hp > 0)
                                p2.hp -= opt.health;
                            opt.health = p2.hp;
                        }
                        scene.AddOperation(opt);
                        break;
                    case Command.EnemySync:
                        if (scene.enemies.ContainsKey(opt.name))
                        {
                            var p2 = scene.enemies[opt.name];
                            p2.pos = opt.position;
                            p2.rotation = opt.rotation;
                        }
                        scene.AddOperation(opt);
                        break;
                    default:
                        scene.AddOperation(opt);
                        break;
                }
            }
            return true;
        }

        public override void OnUpdate()
        {
            scene.AddOperation(new Operation(Command.Input, playerID, position, rotation, direction) {
                cmd1 = fire, cmd2 = jump, health = hp, buffer = extraData
            });
        }

        public override void OnEnter()
        {
            position = new Vector3(RandomHelper.Range(-20f, 20f), 2, RandomHelper.Range(-20f, 20f));
        }

        [Rpc]
        void Revive() 
        {
            hp = 100;
            scene.AddOperation(new Operation(NetCmd.QuitGame, playerID));
            scene.Remove(this);
            Net.Event.EventSystem.AddEvent(1000, ()=> {
                Ser.Instance.EnterScene(this, scene.Name);
            });
            Ser.Instance.SendRT(this, "Revive");
        }

        [Rpc]
        void GetEnemys() {
            object obj = scene.enemies;
            Ser.Instance.SendRT(this, "InsEmys", obj);
        }
    }

    class Scene : NetScene<Peer>
    {
        internal Dictionary<string, Peer> players = new Dictionary<string, Peer>();
        internal Dictionary<string, EnemyData> enemies = new Dictionary<string, EnemyData>();
        public Scene()
        {
            for (int i = 0; i < 50; i++)
            {
                enemies.Add("enemy" + i, new EnemyData("enemy" + i)
                {
                    hp = 100,
                    pos = new Vector3(RandomHelper.Range(-100, 100), -1.1f, RandomHelper.Range(-100, 100))
                });
            }
        }

        public override void OnEnter(Peer client)
        {
            client.scene = this;
            lock(players) players.Add(client.playerID, client);
        }

        public override void OnExit(Peer client)
        {
            lock (players) players.Remove(client.playerID);
        }

        public override void Update(IServerSendHandle<Peer> handle, byte cmd = 19)
        {


            base.Update(handle, cmd);
        }
    }

    class Ser : UdpServer<Peer, Scene> 
    {
        protected override void OnStarting()
        {
            DB.Instance.Load().Wait();
        }

        protected override bool OnUnClientRequest(Peer unClient, RPCModel model)
        {
            switch (model.func)
            {
                case "Register":
                    Register(unClient, model.pars[0].ToString(), model.pars[1].ToString());
                    break;
                case "Login":
                    return Login(unClient, model.pars[0].ToString(), model.pars[1].ToString());
            }
            return false;
        }

        private void Register(Peer unClient, string acc, string pwd)
        {
            if (DB.Instance.Contains(acc))
            {
                SendRT(unClient, "RegisterCallback", "账号已经存在!");
                return;
            }
            var p = new Peer
            {
                playerID = acc,
                data = new PlayerData
                {
                    account = acc,
                    password = pwd
                }
            };
            DB.Instance.AddPlayer(p.data);
            DB.Instance.Save(p.data);
            SendRT(unClient, "RegisterCallback", "注册成功！");
        }

        [Rpc(cmd = NetCmd.SafeCall)]
        private bool Login(Peer unClient, string acc, string pwd)
        {
            if (!DB.Instance.Contains(acc))
            {
                SendRT(unClient, "LoginCallback", false, "账号或密码错误!");
                return false;
            }
            var p = DB.Instance[acc];
            if (p.password != pwd)
            {
                SendRT(unClient, "LoginCallback", false, "账号或密码错误!");
                return false;
            }
            SendRT(unClient, "LoginCallback", true, "登录成功!");
            unClient.data = p;
            return true;
        }

        protected override void OnRemoveClient(Peer client)
        {
            if (client.scene != null)
            {
                if (client.scene.Clients.Count == 1)
                    client.scene.RemoveOperations();
                else
                    client.scene.AddOperation(new Operation(NetCmd.QuitGame, client.playerID));
            }
        }

        [Rpc(NetCmd.SafeCall)]
        void GetEnemys(Peer client)
        {
            object obj = client.scene.enemies.Values.ToList();
            SendRT(client, "InsEmys", obj);
        }
    }
}
